/******************************************************************************
 * 
 * Announce: CSharpKit, Basic algorithms, components and definitions.
 *           Copyright (C) ShenYongchen.
 *           All rights reserved.
 *   Author: 申永辰.郑州 (shenyczz@163.com)
 *  WebSite: http://github.com/shenyczz/CSharpKit
 *
 * THIS CODE IS LICENSED UNDER THE MIT LICENSE (MIT).
 * THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 
 * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
 * IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
 * PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
 * 
******************************************************************************/

using System;
using System.Numerics;
using CSharpKit.Extensions;

namespace CSharpKit.Numerics
{
    /// Stability - 稳定
    /// Dependent on Evaluate
    /// OK
    partial class SpecialFunctions
    {
        /// <summary>
        /// <code>x -> exp(x)-1</code>
        /// </summary>
        /// <param name="power">A number specifying a power.</param>
        /// <returns>Returns <code>exp(power)-1</code>.</returns>
        public static double ExponentialMinusOne(double power)
        {
            double x = System.Math.Abs(power);
            if (x > 0.1)
            {
                return System.Math.Exp(power) - 1.0;
            }

            if (x < x.PositiveEpsilonOf())
            {
                return x;
            }

            // Series Expansion to x^k / k!
            int k = 0;
            double term = 1.0;

            return Evaluate.Series(() =>
                {
                    k++;
                    term *= power;
                    term /= k;
                    return term;
                });
        }

        /// <summary>
        /// Numerically stable hypotenuse of a right angle triangle, i.e. <code>(a,b) -> sqrt(a^2 + b^2)</code>
        /// </summary>
        /// <param name="a">The length of side a of the triangle.</param>
        /// <param name="b">The length of side b of the triangle.</param>
        /// <returns>Returns <code>sqrt(a<sup>2</sup> + b<sup>2</sup>)</code> without underflow/overflow.</returns>
        public static Complex Hypotenuse(Complex a, Complex b)
        {
            if (a.Magnitude > b.Magnitude)
            {
                var r = b.Magnitude / a.Magnitude;
                return a.Magnitude * System.Math.Sqrt(1 + (r * r));
            }

            if (b != 0.0)
            {
                // NOTE (ruegg): not "!b.AlmostZero()" to avoid convergence issues (e.g. in SVD algorithm)
                var r = a.Magnitude / b.Magnitude;
                return b.Magnitude * System.Math.Sqrt(1 + (r * r));
            }

            return 0d;
        }

        /// <summary>
        /// Numerically stable hypotenuse of a right angle triangle, i.e. <code>(a,b) -> sqrt(a^2 + b^2)</code>
        /// </summary>
        /// <param name="a">The length of side a of the triangle.</param>
        /// <param name="b">The length of side b of the triangle.</param>
        /// <returns>Returns <code>sqrt(a<sup>2</sup> + b<sup>2</sup>)</code> without underflow/overflow.</returns>
        // public static Complex32 Hypotenuse(Complex32 a, Complex32 b)
        // {
        //     if (a.Magnitude > b.Magnitude)
        //     {
        //         var r = b.Magnitude/a.Magnitude;
        //         return a.Magnitude*(float)System.Math.Sqrt(1 + (r*r));
        //     }

        //     if (b != 0.0f)
        //     {
        //         // NOTE (ruegg): not "!b.AlmostZero()" to avoid convergence issues (e.g. in SVD algorithm)
        //         var r = a.Magnitude/b.Magnitude;
        //         return b.Magnitude*(float)System.Math.Sqrt(1 + (r*r));
        //     }

        //     return 0f;
        // }

        /// <summary>
        /// Numerically stable hypotenuse of a right angle triangle, i.e. <code>(a,b) -> sqrt(a^2 + b^2)</code>
        /// </summary>
        /// <param name="a">The length of side a of the triangle.</param>
        /// <param name="b">The length of side b of the triangle.</param>
        /// <returns>Returns <code>sqrt(a<sup>2</sup> + b<sup>2</sup>)</code> without underflow/overflow.</returns>
        public static double Hypotenuse(double a, double b)
        {
            if (System.Math.Abs(a) > System.Math.Abs(b))
            {
                double r = b / a;
                return System.Math.Abs(a) * System.Math.Sqrt(1 + (r * r));
            }

            if (b != 0.0)
            {
                // NOTE (ruegg): not "!b.AlmostZero()" to avoid convergence issues (e.g. in SVD algorithm)
                double r = a / b;
                return System.Math.Abs(b) * System.Math.Sqrt(1 + (r * r));
            }

            return 0d;
        }

        /// <summary>
        /// Numerically stable hypotenuse of a right angle triangle, i.e. <code>(a,b) -> sqrt(a^2 + b^2)</code>
        /// </summary>
        /// <param name="a">The length of side a of the triangle.</param>
        /// <param name="b">The length of side b of the triangle.</param>
        /// <returns>Returns <code>sqrt(a<sup>2</sup> + b<sup>2</sup>)</code> without underflow/overflow.</returns>
        public static float Hypotenuse(float a, float b)
        {
            if (System.Math.Abs(a) > System.Math.Abs(b))
            {
                float r = b / a;
                return System.Math.Abs(a) * (float)System.Math.Sqrt(1 + (r * r));
            }

            if (b != 0.0)
            {
                // NOTE (ruegg): not "!b.AlmostZero()" to avoid convergence issues (e.g. in SVD algorithm)
                float r = a / b;
                return System.Math.Abs(b) * (float)System.Math.Sqrt(1 + (r * r));
            }

            return 0f;
        }

        //}}@@@
    }




}
